﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace CleanLite.DynamicApi
{
    /// <summary>
    /// DynamicApi配置相关
    /// </summary>
    public static class DynamicApiConfig
    {
        /// <summary>
        /// 手动配置动态API服务
        /// </summary>
        /// <param name="options">配置选项</param>
        /// <returns></returns>
        public static IServiceCollection AddDynamicApi(this IServiceCollection services, Action<DynamicApiOptions> options)
        {
            services.AddOptions<DynamicApiOptions>()
                .Configure(options);
            services.AddSingleton<DynamicApiConvention>();
            services.AddSingleton<DynamicApiControllerFeatureProvider>();
            return services;
        }

        /// <summary>
        /// 使用动态API中间件
        /// </summary>
        /// <param name="app"></param>
        /// <param name="optionsAction">委托,传入动态API的配置项</param>
        /// <remarks>
        /// <para>关键内容:</para>
        /// <list type="bullet">
        /// <item><see cref="ApplicationPartManager"/>：跟踪可用的应用程序部件和功能提供程序(控制器、视图)</item>
        /// <item><see cref="ControllerFeature"/>：MVC 应用程序中控制器类型的列表。 ControllerFeature可以通过在 组件中要求 ApplicationPartManager 将 用作依赖项，使用ApplicationPartManager在 PartManager 启动期间或PartManager以后阶段可用的 填充 </item>
        /// <item><see cref="ApplicationPartFactory"/>：指定用于从 Assembly合成一个或多个ApplicationPart实例的协定</item>
        /// <item><see cref="ApplicationPartFactory.GetApplicationParts"/>：获取指定 assembly的一个或多个ApplicationPart实例</item>
        /// </list>
        /// </remarks>
        /// <returns></returns>
        public static IApplicationBuilder UseDynamicApi(this IApplicationBuilder app)
        {
            var options = app.ApplicationServices.GetRequiredService<IOptions<DynamicApiOptions>>();

            // 获取 ApplicationPartManager 管理器实例：用于追踪应用程序中的控制器
            var partManager = app.ApplicationServices.GetRequiredService<ApplicationPartManager>();

            // 获取动态API的控制器功能提供者，并将其添加到ApplicationPartManager管理器中
            //其作用是为了识别哪些类应被视为控制器
            var featureProviders = app.ApplicationServices.GetRequiredService<DynamicApiControllerFeatureProvider>();
            partManager.FeatureProviders.Add(featureProviders);

            //ControllerFeature是控制器类型的集合,ApplicationPartManager扫描到的控制器会被添加到ControllerFeature中
            //PopulateFeature:填充到ControllerFeature中
            var feature = new ControllerFeature();
            partManager.PopulateFeature(feature);

            //测试:输出被识别的控制器名称检查是否填充正确或是否填充进去
            foreach (var controller in feature.Controllers)
            {
                Console.WriteLine(controller.FullName);
            }

            //加载指定的程序集，使用ApplicationPartManager扫描其中的程序集,合成ApplicationPart实例
            //用于识别额外的类库下 其他需要动态生成接口的类,将其扫描成控制器
            foreach (var assembly in options.Value.Assemblys)
            {
                //获取指定程序集的 ApplicationPartFactory 实例
                var partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);

                //ApplicationPartFactory.GetApplicationParts(Assembly):获取指定 assembly的一个或多个ApplicationPart实例
                foreach (var part in partFactory.GetApplicationParts(assembly))
                {
                    //ApplicationParts:MVC应用程序的一部分 (例如控制器、视图、Razor页面)
                    partManager.ApplicationParts.Add(part);
                }
            }

            //获取 MVC 选项配置实例
            var mvcOptions = app.ApplicationServices.GetRequiredService<IOptions<MvcOptions>>();
            //获取动态API约定实例
            var dynamicWebApiConvention = app.ApplicationServices.GetRequiredService<DynamicApiConvention>();
            // 添加动态API约定实例，用于配置动态API的路由、Swagger等
            mvcOptions.Value.Conventions.Add(dynamicWebApiConvention);
            return app;
        }
    }
}